/****************************************************************************
**
** WX公众号:Qt历险记
** CSDN:Qt魔术师
**
****************************************************************************/

#include <QCoreApplication>
#include <QFile>
#include <QStringList>
#include <QTextStream>
#include <QXmlStreamReader>

/*
 此类的唯一目的是创建翻译上下文。
*/
class XmlStreamLint
{
public:
    // 从字面意思：声明tr函数 tr()函数就是用来处理国际化语言的 因为tr()时QObject的方法QObject::tr() or QObject::trUtf8()，而增加头文件会增加编译的时间
    // 这个宏的功能：XmlStreamLint可以调用以下两个函数
    /*  static inline QString tr(const char *sourceText,
                           const char *comment = 0);
        static inline QString trUtf8(const char *sourceText,
                               const char *comment = 0);
    */
    Q_DECLARE_TR_FUNCTIONS(XmlStreamLint) // 必须出现在类定义的最顶部
};

int main(int argc, char *argv[])
{
    enum ExitCode
    {
        Success,
        ParseFailure,
        ArgumentError,
        WriteError,
        FileFailure
    };

    QCoreApplication app(argc, argv);

    QTextStream errorStream(stderr); // 标准IO出错

    errorStream <<"argc = "<<argc<<Qt::endl;
    errorStream <<"arg0 = "<<QCoreApplication::arguments().at(0)
                <<Qt::endl<<"arg1 = "<<QCoreApplication::arguments().at(1)<<Qt::endl
                <<Qt::endl<<"arg2 = "<<QCoreApplication::arguments().at(2)<<Qt::endl; // 外部参数

    // 命令行参数个数可以在编译时指定:点击最左侧项目->点击Run按钮->在运行的下面第二行：mmand linearguments:行编辑框输入参数,参数之间空格分隔,注意一个完整的参数中不能有空格不然被分成了两个参数
    if (argc != 3)
    {
        errorStream << XmlStreamLint::tr(
                       "Usage: xmlstreamlint <path to XML file>\n");
        return ArgumentError;
    }

    // 参数arg0是默认应用程序编译生成的.exe文件的绝对路径，arg1才是我们输入的第一个命令行参数
    QString inputFilePath(QCoreApplication::arguments().at(1));
    QFile inputFile(inputFilePath);

    // 文件不存在
    if (!QFile::exists(inputFilePath))
    {
        errorStream << XmlStreamLint::tr(
                       "File %1 does not exist.\n").arg(inputFilePath);
        return FileFailure;

    }
    // 文件打开失败
    else if (!inputFile.open(QIODevice::ReadOnly)) {
        errorStream << XmlStreamLint::tr(
                       "Failed to open file %1.\n").arg(inputFilePath);
        return FileFailure;
    }

    // 写入我指定的另一个空的XML文件
    QString outFilePath(QCoreApplication::arguments().at(2));
    QFile outputFile(outFilePath);
    if (!outputFile.open(QIODevice::WriteOnly))
    {
        errorStream << XmlStreamLint::tr("Failed to open " + outputFile.fileName().toUtf8());
        return WriteError;
    }

//! [第一步]
//! // qxml流阅读器类提供了一个快速解析器，可以通过简单的流api读取格式良好的xml
    QXmlStreamReader reader(&inputFile);
    // qxml流媒体写入器类提供了一个具有简单流媒体api的xml写入器
    QXmlStreamWriter writer(&outputFile);
//! [end]

//! [第二步] 按行读取XML文件
    while (!reader.atEnd())
    {
        reader.readNext();

        if (reader.error()) // 解析错误 只是在那行那列
        {
            errorStream << XmlStreamLint::tr(
                           "Error: %1 in file %2 at line %3, column %4.\n").arg(
                               reader.errorString(), inputFilePath,
                               QString::number(reader.lineNumber()),
                               QString::number(reader.columnNumber()));
            return ParseFailure;
//! [end]

//! [第三步]
        }
        else {
            // 写入读者的当前状态。支持所有可能的有效状态。此函数的目的是支持对xml数据的链式处理。
            writer.writeCurrentToken(reader); // 读取的内容写入到文件中
        }
    }
//! [end]

    return Success;
}
